/**
 * 使用方法：
 *  const app = new App(); 
    app.setCameraPosition(0, 10, 30); 相机位置
    app.addLight(); 添加灯光
    app.addBackground("sunflowers_puresky"); 添加HDRI
    app.addPlane(500, 500, 80); 添加平面
    app.addAxesHelper(4); 添加坐标辅助器
 * **/
let envTexture: THREE.Texture;

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { TransformControls } from "three/examples/jsm/controls/TransformControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";

import disposeObject from "./disposeObject";

const loader = new GLTFLoader();

export default class App {
  scene: THREE.Scene;
  camera: THREE.PerspectiveCamera;
  renderer: THREE.WebGLRenderer;
  orbitControls: OrbitControls;
  transformControls: TransformControls;
  container: HTMLElement;
  modelGroup!: THREE.Group;
  constructor(container: HTMLElement) {
    THREE.Cache.enabled = true;
    // 创建场景
    this.scene = new THREE.Scene();
    // 创建相机
    this.camera = new THREE.PerspectiveCamera(
      60,
      container.clientWidth / container.clientHeight,
      0.1,
      10000
    );
    this.camera.position.set(0, 0, 5);
    this.container = container;
    // 创建渲染器
    this.renderer = new THREE.WebGLRenderer({ antialias: true });
    this.renderer.autoClear = false;
    this.renderer.setSize(container.clientWidth, container.clientHeight);
    container.appendChild(this.renderer.domElement);
    this.orbitControls = new OrbitControls(
      this.camera,
      this.renderer.domElement
    );
    this.transformControls = new TransformControls(
      this.camera,
      this.renderer.domElement
    );
    this.modelGroup = new THREE.Group();
    this.scene.add(this.modelGroup);
  }

  // 增加光源
  addLight() {
    this.scene.add(new THREE.AmbientLight(0xffffff, 3));
    const light = new THREE.SpotLight(0xffffff, 4.5);
    light.position.set(0, 1500, 0);
    // light.position.set(0, 4, 28);
    light.angle = Math.PI * 0.2;
    light.decay = 0;
    light.castShadow = true;
    light.shadow.camera.near = 200;
    light.shadow.camera.far = 2000;
    light.shadow.bias = -0.000222;
    light.shadow.mapSize.width = 1024;
    light.shadow.mapSize.height = 1024;
    this.scene.add(light);
    // const pointLight = new THREE.PointLight(0xfffff8, 1);
    // pointLight.position.set(10, 4, 10);
    // pointLight.distance = 50;
    // this.scene.add(pointLight);
    // 点光源-正后冷
    // const pointLight2 = new THREE.PointLight(0xf8f8ff, 0.5);
    // pointLight2.position.set(0, 4, -10);
    // pointLight2.distance = 50;
    // this.scene.add(pointLight2);
    // 平行光源
    const directionalLight = new THREE.DirectionalLight();
    directionalLight.position.set(1, 5, -1);
    directionalLight.intensity = 1;
    this.scene.add(directionalLight);
  }

  // 添加背景
  addBackground(name: string, showSky: boolean = false) {
    const textureLoader = new THREE.TextureLoader();
    envTexture = textureLoader.load("/assets/HDRI/" + name + ".jpg");
    envTexture.mapping = THREE.EquirectangularReflectionMapping;
    envTexture.colorSpace = THREE.SRGBColorSpace;
    if (showSky) {
      this.scene.background = envTexture;
      this.scene.fog = new THREE.FogExp2(0x3c5384, 0.00055);
    } else {
      this.scene.environment = envTexture;
    }
  }

  // 添加地板  [type默认 stone 可选 square]
  addPlane(
    x: number,
    y: number,
    r: number,
    type: string = "stone",
    position: THREE.Vector3 = new THREE.Vector3(0, 0, 0)
  ) {
    const loader1 = new THREE.TextureLoader();
    const floorGeometry = new THREE.PlaneGeometry(x, y);
    const texture = loader1.load(
      "/assets/textures/textures/" + type + "_diff_2k.jpg"
    );
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set(r, r);
    texture.anisotropy = 4;

    // const armTexture = loader1.load(
    //   '/assets/textures/textures/' + type + '_arm_2k.jpg'
    // );
    // armTexture.wrapS = THREE.RepeatWrapping;
    // armTexture.wrapT = THREE.RepeatWrapping;
    // armTexture.repeat.set(r, r);

    // const normalMap = loader1.load(
    //   '/assets/textures/textures/' + type + '_nor_2k.jpg'
    // );
    // normalMap.wrapS = THREE.RepeatWrapping;
    // normalMap.wrapT = THREE.RepeatWrapping;
    // normalMap.repeat.set(r, r);

    const floorMaterial = new THREE.MeshStandardMaterial({
      map: texture,
      roughness: 0.8,
      // color: 0xffffff,
      // color: 0x2e3683,
      // color: 0x4b70abd9,
      color: 0x37527d,
      // color: 0x2b3f61,
      metalness: 0.2,
      bumpScale: 0.0005,

      // normalMap: normalMap,
      // aoMap: armTexture,
      // roughnessMap: armTexture,
      // metalnessMap: armTexture,
      // color: type === 'stone' ? 0x090909 : '',
    });

    const floor = new THREE.Mesh(floorGeometry, floorMaterial);
    floor.position.set(position.x, position.y - 4, position.z);
    floor.rotation.x = -Math.PI / 2; // 使地板平行于场景
    this.scene.add(floor);
  }

  // 处理窗口大小变化的逻辑
  onWindowResize() {
    if (this.camera) {
      this.camera.aspect =
        this.container.clientWidth / this.container.clientHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(
        this.container.clientWidth,
        this.container.clientHeight
      );
    }
  }

  // 增加场景辅助器 length 线段长度
  addAxesHelper(length: number) {
    const axesHelper = new THREE.AxesHelper(length);
    this.scene.add(axesHelper);
  }

  // 设置相机的位置
  setCameraPosition(x: number, y: number, z: number) {
    this.orbitControls.object.position.set(x, y, z);
  }
  // 设置相机朝向
  setCameraOrientation(x: number, y: number, z: number) {
    this.camera.lookAt(x, y, z);
  }

  // 设置渲染器的大小
  setRendererSize(width: number, height: number) {
    this.renderer.setSize(width, height);
  }

  // 视角控制
  viewingAngleControl() {
    this.orbitControls.screenSpacePanning = false;
    this.orbitControls.enableDamping = true; // 启用阻尼感
    this.orbitControls.minPolarAngle = Math.PI / 6;
    this.orbitControls.maxPolarAngle = Math.PI / 2.001;
  }

  // 开启阴影效果
  shadowMap() {
    this.renderer.shadowMap.enabled = true;
  }

  // 添加模型场景
  addHouse(
    model: string,
    scene: THREE.Scene | THREE.Group,
    applyStyle?: (target: THREE.Object3D) => void
  ) {
    loader.load(
      "/assets/three/models/" + model + ".glb",
      function (gltf) {
        const loadedModel = gltf.scene;
        loadedModel.position.x += 3;
        loadedModel.position.z -= 1;
        loadedModel.name = "House";
        if (applyStyle) applyStyle(loadedModel);
        loadedModel.traverse((node) => {
          if (node instanceof THREE.Mesh) {
            node.receiveShadow = true; // 接收阴影
          }
        });
        scene.add(loadedModel);
      },
      undefined,
      function (err) {
        console.log(err);
      }
    );
  }
  // 场景卸载
  dispose() {
    console.log("dispose已执行");
    disposeObject(this.scene);
    this.renderer.dispose();
    this.renderer.forceContextLoss();
  }

  // 渲染场景
  render(scene?: THREE.Scene, camera?: THREE.PerspectiveCamera) {
    this.renderer.clear();
    this.renderer.render(this.scene, this.camera);
    this.renderer.clearDepth();
    if (scene && camera) {
      this.renderer.render(scene, camera);
    }
  }
}
